package com.googlecode.kipler.satisfiability.blocking.abox;

import java.util.Iterator;
import java.util.List;

import com.googlecode.kipler.container.dl.ABox;
import com.googlecode.kipler.container.dl.Individual;
import com.googlecode.kipler.container.dl.SHOIQABox;
import com.googlecode.kipler.container.dl.operational.AncestorCollector;
import com.googlecode.kipler.container.dl.operational.SHOIQAncestorCollector;


/**
 * 
 * @author İnanç Seylan
 *
 */
public class SHOIQDoubleBlocking implements ABoxBlockingStrategy {

	private SHOIQABox aBox;

	protected SHOIQABox getABox() {
		return aBox;
	}

	protected void setABox(SHOIQABox abox) {
		this.aBox = abox;
	}

	public boolean isBlocked(ABox abox, String indvName) {
		setABox((SHOIQABox) abox);
		return isLabelBlocked(indvName) || isIndirectlyBlocked(abox, indvName);
	}

	public boolean isIndirectlyBlocked(ABox abox, String indvName) {
		setABox((SHOIQABox) abox);
		boolean result = false;
		Individual x = abox.getIndividual(indvName);
		if (getABox().isBlockable(x)) {
			for (Individual ancestor : new SHOIQAncestorCollector(getABox(), x)
					.collect()) {
				if (isLabelBlocked(ancestor.getName())) {
					result = true;
					break;
				}
			}
		}
		return result;
	}

	private boolean isLabelBlocked(String individual) {
		boolean result = false;
		Individual x = getABox().getIndividual(individual);
		if (getABox().isBlockable(x)) {
			AncestorCollector ancestorCollector = new SHOIQAncestorCollector(
					getABox(), x);
			List<Individual> xAncestors = ancestorCollector.collect();
			/*
			 * we need at least two ancestors (yPrime can be a nominal so it
			 * does not need to be included in the ancestors list)
			 */
			if (xAncestors.size() >= 2) {
				Iterator<Individual> i = xAncestors.iterator();
				/*
				 * first element is guaranteed to be x's predecessor, i.e.,
				 * xPrime
				 */
				Individual xPrime = i.next();
				while (i.hasNext()) {
					/*
					 * Iteration guarantees that y is different from xPrime. y
					 * is also blockable.
					 */
					Individual y = i.next();
					/*
					 * yPrime is not necessarily in the ancestors list because
					 * it might be a nominal
					 */
					Individual yPrime = getPredecessor(y);
					/*
					 * ancestors list guarantees that all nodes on the path from
					 * y to x are blockable
					 */
					if (yPrime != null
							&& x.hasSameConceptsAs(y)
							&& xPrime.hasSameConceptsAs(yPrime)
							&& getABox().getEdges(xPrime, x).equals(
									getABox().getEdges(yPrime, y))) {
						result = true;
						break;
					}
				}
			}
		}
		return result;
	}

	private Individual getPredecessor(Individual individual) {
		Iterator<Individual> i = aBox.predecessorIterator(individual);
		Individual result = i.hasNext() ? i.next() : null;
		return result;
	}

}
